package summoning;

import impsoft.bots.reflection.Interface;
import impsoft.bots.reflection.NPC;
import impsoft.bots.reflection.NPCIterator;
import impsoft.bots.reflection.PhysicalObject;
import impsoft.scripting.ibot.builtin.ocr.Menu;
import impsoft.scripting.ibot.enums.Skill;
import impsoft.scripting.ibot.itemrec.ItemCondition;
import impsoft.scripting.ibot.itemrec.ItemContains;
import impsoft.scripting.ibot.structs.AryanTile;
import impsoft.scripting.types.ColorSkeltonScriptable;
import impsoft.utils.general.Timer;
import impsoft.utils.uber.UberClickOptions;
import impsoft.utils.uber.UberScriptUtils;

import java.awt.Rectangle;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.regex.Pattern;

import minimapbuttons.MiniMapButtonOption;
import bergCoder.ClosestTile;

@Deprecated
public class Summoning {
	// TODO: Credits to Perfecticus, most of this originally came from his
	// publicly release summoning api.
	private ColorSkeltonScriptable cs;

	private static Rectangle summoning_button = new Rectangle(697, 137, 19, 14);
	public static final AryanTile[] summoningObeliskLocs = { //
	new AryanTile(2111, 3917), // lunar isle
			new AryanTile(2177, 3134), // tyras camp
			new AryanTile(2307, 3196), // lletya
			new AryanTile(2317, 3804), // nietznot
			new AryanTile(2405, 4443), // dat fairy place
			new AryanTile(2415, 3796), // jatizo
			new AryanTile(2458, 3442), // tree gnome
			new AryanTile(2463, 3087), // castlewars
			new AryanTile(2499, 2832), // ooglog
			new AryanTile(2516, 3591), // lighthouse
			new AryanTile(2527, 3360), // combat training camp
			new AryanTile(2533, 3255), // battlefield/west of ourania
			new AryanTile(2549, 2962), // feldip hills
			new AryanTile(2593, 3423), // fishing guild
			new AryanTile(2606, 3854), // miscellania
			new AryanTile(2626, 3155), // port khazard
			new AryanTile(2674, 3640), // relleka
			new AryanTile(2778, 2764), // ape atoll
			new AryanTile(2820, 2967), // shilo village
			new AryanTile(2848, 3161), // karamja volcano
			new AryanTile(2851, 3027), // karamja near nat altar
			new AryanTile(2853, 3439), // catherby
			new AryanTile(2886, 3676), // trollheim
			new AryanTile(2916, 3520), // hero's guild/buthorpe
			new AryanTile(3000, 3193), // port sarim
			new AryanTile(3094, 3220), // drayno village
			new AryanTile(3128, 3515), // edgeville
			new AryanTile(3306, 3244), // duel arean
			new AryanTile(3325, 2803), // sophanem
			new AryanTile(3333, 3000), // pollivneach
			new AryanTile(3452, 3491), // canifis
			new AryanTile(3479, 3253), // morrton
			new AryanTile(3660, 3538), // ectofuntus
	};

	public static final int[] obeliskIds = { 29938, 29939, 29943, 29944, 29945, 29951, 29952, 29953, 29954, 29957,
			29959, 29992 };

	public Summoning(ColorSkeltonScriptable cs) {
		this.cs = cs;
	}

	public static Familiar[] getAttackFamiliars() {
		return new Familiar[] { Familiar.DREADFOWL, Familiar.THORNY_SNAIL, Familiar.DESERT_WYRM,
				Familiar.SPIRIT_TZ_KIH, Familiar.SPIRIT_KALPHITE, Familiar.VAMPITE_BAT, Familiar.BRONZE_MINOTAUR,
				Familiar.IRON_MINOTAUR, Familiar.SPIRIT_JELLY, Familiar.STEEL_MINOTAUR, Familiar.SPIRIT_KYATT,
				Familiar.SPIRIT_GRAAHK, Familiar.KARAMTHULHU_OVERLORD, Familiar.SMOKE_DEVIL, Familiar.MITHRIL_MINOTAUR,
				Familiar.BARKER_TOAD, Familiar.ARCTIC_BEAR, Familiar.GRANITE_LOBSTER, Familiar.ADAMANT_MINOTAUR,
				Familiar.TALON_BEAST, Familiar.GIANT_ENT, Familiar.SPIRIT_DAGANNOTH, Familiar.RUNE_MINOTAUR,
				Familiar.IRON_TITAN, Familiar.STEEL_TITAN };
	}

	public static Familiar[] getBOBFamiliars() {
		return new Familiar[] { Familiar.THORNY_SNAIL, Familiar.SPIRIT_KALPHITE, Familiar.BULL_ANT,
				Familiar.SPIRIT_TERRORBIRD, Familiar.ABYSSAL_PARASITE, Familiar.ABYSSAL_LURKER, Familiar.WAR_TORTOISE,
				Familiar.ABYSSAL_TITAN, Familiar.PACK_YAK };
	}

	public boolean useAttackScroll(Familiar familiar) throws InterruptedException {
		for (Familiar familiar2 : getAttackFamiliars()) {
			if (familiar.equals(familiar2) && cs.theTabs.Inventory.count(familiar.getScrollName()) > 0) {
				if (familiar.getRequiredSpecial() >= getSpecialPoints()) {
					return doMiniMapButtonAction(MiniMapButtonOption.SPECIAL_MOVE);
				}
			}
		}

		return false;
	}

	@SuppressWarnings("unchecked")
	public boolean depositAll(ItemCondition condition, boolean close_after) throws InterruptedException {
		if (!isInventoryUp()) {
			NPC familiar = getFamiliar();
			if (familiar == null) {
				return false;
			}
			Timer t = new Timer(5000);
			if (isInventoryUp()
					|| UberScriptUtils.clickWorldObject(cs, familiar,
							Pattern.compile(".*" + familiar.getName() + ".*", Pattern.CASE_INSENSITIVE),
							Pattern.compile(".*Store.*", Pattern.CASE_INSENSITIVE),
							EnumSet.of(UberClickOptions.WALK_GAME_ONLY, UberClickOptions.USE_MENU))
							.possiblySuccessful()) {
				while (!t.isUp() && !isInventoryUp()) {
					cs.sleep(100);
				}
			}
		}

		if (isInventoryUp()) {
			if (isInventoryFull()) {
				return true;
			}
			while (cs.theTabs.Inventory.countEmptySlots() < 28 && !isInventoryFull()
					&& doInventoryItem(condition, "Store-All", false)) {
				cs.sleep(100);
			}
			if (close_after) {
				closeInventory();
			}
			return true;
		}

		return false;
	}

	public boolean closeInventory() throws InterruptedException {
		Rectangle close_inventory = new Rectangle(418 + cs.getReflectionFields().GAME_INTERFACE_OFF_X,
				34 + cs.getReflectionFields().GAME_INTERFACE_OFF_Y, 13, 13);

		if (isInventoryUp()) {
			Timer t = new Timer(1500);
			cs.mouseClickLeft(close_inventory);
			while (!t.isUp() && isInventoryUp()) {
				cs.sleep(100);
			}
			if (!isInventoryUp()) {
				return true;
			}
		}
		return !isInventoryUp();

	}

	@SuppressWarnings("unchecked")
	public boolean withdrawAll(boolean close_after) throws InterruptedException {
		if (!isInventoryUp()) {
			NPC familiar = getFamiliar();
			if (familiar == null) {
				return false;
			}

			Timer t = new Timer(5000);
			if (isInventoryUp()
					|| UberScriptUtils.clickWorldObject(cs, familiar,
							Pattern.compile(".*" + familiar.getName() + ".*", Pattern.CASE_INSENSITIVE),
							Pattern.compile(".*Store.*", Pattern.CASE_INSENSITIVE),
							EnumSet.of(UberClickOptions.WALK_GAME_ONLY, UberClickOptions.USE_MENU))
							.possiblySuccessful()) {
				while (!t.isUp() && !isInventoryUp()) {
					cs.sleep(100);
				}
			}
		}

		if (isInventoryUp()) {
			for (int i = 0; i < 30; i++) {
				Interface[] slots = getInventorySlots();
				if (slots != null && slots.length > 0 && slots[i].getItemId() != -1) {
					Rectangle area = slots[i].getCalculatedArea2();
					if (area != null) {
						if (!area.contains(cs.getCurrentMouseX(), cs.getCurrentMouseY())) {
							cs.mouseMove(area);
						}
						if (area.contains(cs.getCurrentMouseX(), cs.getCurrentMouseY())) {
							String tt = null;
							String action = "Withdraw-All";
							if ((tt = cs.theTopText.getTopText().toLowerCase()) != null
									&& (action == null || action == "" || tt.contains(action))) {
								cs.mouseClickLeft(cs.getCurrentMouseX(), cs.getCurrentMouseY());
							} else {
								cs.mouseClickRight(cs.getCurrentMouseX(), cs.getCurrentMouseY());
								Timer t = new Timer(250);
								while (!t.isUp() && cs.theMenuFinder.getMenu() == null) {
									cs.sleep(50);
								}
								Menu m = null;
								if ((m = cs.theMenuFinder.getMenu()) != null) {
									if (!m.contains(action)) {
										cs.mouseClickLeft(cs.getCurrentMouseXY());
									}
									if (m.clickContains(action)) {
										t = new Timer(1000);
										while (!t.isUp() && slots[i].getItemId() != -1) {
											cs.sleep(100);
										}
									}

								}
							}
						}
					}
				}
			}

			if (close_after) {
				closeInventory();
			}
			return getFreeInventorySlots() == 30;
		}
		return false;
	}

	/*
	 * Custom made inventory methods that are more humanlike than the inbuilt
	 * ones.
	 */
	public boolean doInventoryItem(ItemCondition it, String action, boolean waitForChange) throws InterruptedException {
		return GeneralUtils.inventoryUtils.doInventory(it, action, waitForChange);
	}

	@SuppressWarnings("unchecked")
	public boolean restorePoints(boolean use_obelisk) throws InterruptedException {
		if (use_obelisk) {
			cs.log("[Summoning] Using obelisk to restore summoning points");

			Arrays.sort(summoningObeliskLocs, new ClosestTile(cs));
			AryanTile obelisk = summoningObeliskLocs[0];// cs.ak4.getSortedTiles(summoningObeliskTiles)[0];

			if (obelisk.distanceTo(cs.getLocation()) < 100) {
				GeneralUtils.walkingUtils.walkTo(obelisk, 4);

				PhysicalObject obeliskObject = GeneralUtils.miscUtils.getPhysicalObject(obeliskIds, cs.getLocation(),
						10);
				if (obeliskObject != null) {
					GeneralUtils.walkingUtils.sleepUntilNotMoving();
				}
			}
		} else {
			if (GeneralUtils.potionUtils.usePotion(CombatPotion.SUMMONING)) {
				cs.log("[Summoning] Drinking summoning potion to restore summoning points");
				return true;
			} else if (GeneralUtils.potionUtils.usePotion(CombatPotion.RESTORE)) {
				cs.log("[Summoning] Drinking restore potion to restore summoning points");
				return true;
			}
		}

		return false;
	}

	public boolean renewFamiliar(Familiar familiar, boolean use_obelisk) throws InterruptedException {
		cs.theTabs.Inventory.setSelected();
		NPC f = getFamiliar();
		if (canSummonPouch(familiar)) {
			if (getSummoningPoints() < 15) {
				restorePoints(use_obelisk);
				Timer t = new Timer(1000);
				while (!t.isUp() && !canSummonPouch(familiar)) {
					cs.sleep(100);
				}
			}
			if (getSummoningPoints() > 15) {
				if (f != null && f.getName().equals(familiar.getName())) {
					if (!summoning_button.contains(cs.getCurrentMouseX(), cs.getCurrentMouseY())) {
						cs.mouseMove(summoning_button);
					}
					if (summoning_button.contains(cs.getCurrentMouseX(), cs.getCurrentMouseY())) {
						String tt = null;
						String action = "Renew";

						if ((tt = cs.theTopText.getTopText().toLowerCase()) != null
								&& (action == null || action == "" || tt.contains(action))) {
							cs.mouseClickLeft(cs.getCurrentMouseX(), cs.getCurrentMouseY());
							Timer t = new Timer(3000);
							while (!t.isUp() && getFamiliar() == null) {
								cs.sleep(100);
							}
							cs.log("[Summoning] Renewed familiar (" + familiar.getName() + ")");
							return true;
						} else {
							cs.mouseClickRight(cs.getCurrentMouseX(), cs.getCurrentMouseY());
							Timer t = new Timer(250);
							while (!t.isUp() && cs.theMenuFinder.getMenu() == null) {
								cs.sleep(50);
							}
							Menu m = null;
							if ((m = cs.theMenuFinder.getMenu()) != null) {
								if (!m.contains(action)) {

									cs.mouseClickLeft(cs.getCurrentMouseXY());
									return false;
								}
								if (m.clickContains(action)) {
									t = new Timer(3000);
									while (!t.isUp() && getFamiliar() == null) {
										cs.sleep(100);
									}
									cs.log("[Summoning] Renewed familiar (" + familiar.getName() + ")");
									return true;
								}
							}
						}
					}
				} else {
					if (doInventoryItem(new ItemContains(familiar.getName() + " pouch"), "Summon", true)) {
						Timer t = new Timer(3000);
						while (!t.isUp() && getFamiliar() == null) {
							cs.sleep(100);
						}
						cs.log("[Summoning] Summoned familiar (" + familiar.getName() + ")");
						return true;
					}
				}
			}
		}
		return false;
	}

	public boolean doMiniMapButtonAction(MiniMapButtonOption option) throws InterruptedException {
		Rectangle r = getMiniMapButtonArea();
		if (r != null) {
			cs.mouseMove(r);
			if (cs.theTopText.getTopText().contains(option.getTopText())) {
				cs.mouseClickLeft(cs.getCurrentMouseXY());
				return true;
			} else {
				cs.mouseClickRight(cs.getCurrentMouseXY());
				if (waitForMenu()) {
					return cs.theMenuFinder.doMenuContains(option.getTopText());
				}
			}
		}
		return false;
	}

	public boolean dismissFamiliar() throws InterruptedException {
		return isFamiliarSummoned() ? doMiniMapButtonAction(MiniMapButtonOption.DISMISS_FOLLOWER)
				&& !isFamiliarSummoned() : true;
	}

	public int getSummoningPercentage() throws InterruptedException {
		int summoning = getSummoningPoints();
		int lvl = cs.theTabs.Statistics.getStatBottom(Skill.SUMMONING);
		return lvl > 0 && summoning > 0 ? (int) ((double) 100 * summoning / (lvl * 10)) : 100;
	}

	public int getSummoningPoints() {
		try {
			return Integer.parseInt(cs.getInterfaceAtIndex(747, 5).getText());
		} catch (Throwable t) {
			return 0;
		}
	}

	public int getSpecialPoints() {
		return cs.getSettingArray()[1177];
	}

	public double getFamiliarTime() {
		return (double) (cs.getSettingArray()[1176] >> 6) / 2;
	}

	public boolean isFamiliarSummoned() {
		return getFamiliarTime() > 0;
	}

	public Familiar getFamiliarInfo(String name) {
		for (Familiar f : Familiar.values()) {
			if (f.getName().equalsIgnoreCase(name)) {
				return f;
			}
		}
		return null;
	}

	public int getFreeInventorySlots() {
		int count = 0;
		if (isInventoryUp()) {
			Interface bob = cs.getInterfaceAtIndex(671, 27);
			if (bob != null && bob.isValid()) {
				Interface[] bobSlots = bob.getChildren();
				for (int i = 0; i < 30; i++) {
					if (bobSlots.length < i) {
						continue;
					}
					if (bobSlots[i].getItemId() == -1) {
						count++;
					}
				}
			}
		}
		return count;
	}

	public Interface[] getInventorySlots() {
		return cs.getInterfaceAtIndex(671, 27).getChildren();
	}

	public NPC getFamiliar() {
		NPC closest = null;
		int distance = 1000;
		if (getFamiliarTime() > 0) {
			for (NPCIterator npci = cs.getNPCIterator(); npci.hasNext();) {
				NPC npc = npci.next();
				for (Familiar fs : Familiar.values()) {
					if (npc.getName().contains(fs.getName()) && npc.isInteractingWithMyPlayer()) {
						return npc;
					}
				}
			}
			for (NPCIterator npci = cs.getNPCIterator(); npci.hasNext();) {
				NPC npc = npci.next();
				for (Familiar fs : Familiar.values()) {
					if (npc.getName().contains(fs.getName()) && !npc.isInteractingWithOtherPlayer()
							&& npc.getLocation().distanceTo(cs.getLocation()) < distance) {
						closest = npc;
						distance = npc.getLocation().distanceTo(cs.getLocation());
					}
				}
			}
		}
		return closest;
	}

	private Rectangle getMiniMapButtonArea() {
		Rectangle r = null;
		Interface f = cs.getInterfaceAtIndex(747, 3);
		if (f != null && f.isValid()) {
			r = f.getCalculatedArea(cs.getReflectionFields().GAME_INTERFACE_OFF_X + 686,
					cs.getReflectionFields().GAME_INTERFACE_OFF_Y + 123);
		}
		return r;
	}

	public String getFamiliarName() throws InterruptedException {
		// Interface familiarNameFace =cs.getInterfaceAtIndex(662, 54);
		if (isFamiliarSummoned()) {
			return cs.getInterfaceAtIndex(662, 54).getText();
		} else {
			return null;
		}
	}

	public MiniMapButtonOption getSelectedMiniMapOption() {
		MiniMapButtonOption selected = null;
		switch (cs.getSettingArray()[1493]) {
		case 0:
			selected = MiniMapButtonOption.FOLLOWER_DETAILS;
			break;
		case 1:
			selected = MiniMapButtonOption.SPECIAL_MOVE;
			break;
		case 2:
			selected = MiniMapButtonOption.ATTACK;
			break;
		case 3:
			selected = MiniMapButtonOption.CALL_FOLLOWER;
			break;
		case 4:
			selected = MiniMapButtonOption.DISMISS_FOLLOWER;
			break;
		case 5:
			selected = MiniMapButtonOption.TAKE_BOB;
			break;
		case 6:
			selected = MiniMapButtonOption.RENEW_FAMILIAR;
			break;
		}
		return selected;
	}

	private MiniMapButtonOption getSelectedTempMiniMapOption() {
		MiniMapButtonOption selected = null;
		switch (cs.getSettingArray()[1494]) {
		case 0:
			selected = MiniMapButtonOption.FOLLOWER_DETAILS;
			break;
		case 1:
			selected = MiniMapButtonOption.SPECIAL_MOVE;
			break;
		case 2:
			selected = MiniMapButtonOption.ATTACK;
			break;
		case 3:
			selected = MiniMapButtonOption.CALL_FOLLOWER;
			break;
		case 4:
			selected = MiniMapButtonOption.DISMISS_FOLLOWER;
			break;
		case 5:
			selected = MiniMapButtonOption.TAKE_BOB;
			break;
		case 6:
			selected = MiniMapButtonOption.RENEW_FAMILIAR;
			break;

		}
		return selected;
	}

	public boolean setLeftClickOption(MiniMapButtonOption option) throws InterruptedException {
		if (option != null && option != MiniMapButtonOption.SELECT_LEFT_CLICK_OPTION && isFamiliarSummoned()
				&& option != getSelectedMiniMapOption()) {
			Rectangle r = getMiniMapButtonArea();
			if (r != null) {
				cs.mouseClickRight(r);
				waitForMenu();
				if (cs.theMenuFinder.isMenuUp()) {
					cs.theMenuFinder.doMenuContains(option.getTopText());
				} else {
					setLeftClickOption(option);
				}
				do {
					r = null;
					Timer t = new Timer(5000);
					while (r == null && t.isNotUp()) {
						r = getleftClickOptionArea(option);
					}
					if (r != null) {
						cs.mouseClickLeft(r);
					}
				} while (getSelectedTempMiniMapOption() != option && isFamiliarSummoned());

				if (getSelectedTempMiniMapOption() == option) {
					r = null;
					Timer t = new Timer(5000);
					while (r == null && t.isNotUp()) {
						r = getConfirmOptionArea();
					}
					if (r != null) {
						cs.mouseClickLeft(r);
					}
				}
			}
		}
		return option == getSelectedMiniMapOption();
	}

	@SuppressWarnings("static-access")
	private Rectangle getleftClickOptionArea(MiniMapButtonOption option) throws InterruptedException {
		Rectangle r = null;
		if (option != null) {
			Interface f = cs.getInterfaceAtIndex(option.masterIndex, option.getParentIndex());
			if (f != null && f.isValid()) {
				r = f.getCalculatedArea(cs.getReflectionFields().GAME_INTERFACE_OFF_X + 542,
						cs.getReflectionFields().GAME_INTERFACE_OFF_Y + 201);
			}
		}
		return r;
	}

	private Rectangle getConfirmOptionArea() {
		Rectangle r = null;

		Interface f = cs.getInterfaceAtIndex(MiniMapButtonOption.masterIndex, 5);
		if (f != null && f.isValid()) {
			r = f.getCalculatedArea(cs.getReflectionFields().GAME_INTERFACE_OFF_X + 542,
					cs.getReflectionFields().GAME_INTERFACE_OFF_Y + 201);
		}
		return r;
	}

	private boolean waitForMenu() throws InterruptedException {
		Timer t = new Timer(1000);
		while (!cs.theMenuFinder.isMenuUp() && t.isNotUp()) {
			cs.sleep(100);
		}
		return cs.theMenuFinder.isMenuUp();
	}

	public boolean canSummonPouch(Familiar f) throws InterruptedException {
		return (getSummoningPoints() > 15 || hasRestoration())
				&& cs.theTabs.Inventory.count(f.getName() + " pouch") > 0;
	}

	public boolean hasRestoration() throws InterruptedException {
		return cs.theTabs.Inventory.count("Summoning potion") > 0 || cs.theTabs.Inventory.count("Super restore") > 0;
	}

	public boolean isInventoryUp() {
		try {
			return cs.getInterfaceAtIndex(671, 28).isValid();
		} catch (Throwable t) {
			return false;
		}
	}

	public boolean isInventoryFull() {
		NPC npc = getFamiliar();
		if (npc != null) {
			Familiar familiar = getFamiliarInfo(npc.getName());
			if (familiar != null && familiar.getInventorySpace() > 0) {
				return 30 - familiar.getInventorySpace() == getFreeInventorySlots();
			}
		}
		return false;
	}

}